#include "common.h"
#include <SDL2/SDL.h>
#include <thread>
#include <chrono>

class VideoPlayer {
public:
    VideoPlayer() : fmt_ctx(nullptr), codec_ctx(nullptr), texture(nullptr), 
                    renderer(nullptr), window(nullptr), is_playing(false) {}
    
    ~VideoPlayer() {
        cleanup();
    }
    
    bool open(const std::string& filename) {
        int ret = avformat_open_input(&fmt_ctx, filename.c_str(), nullptr, nullptr);
        if (ret < 0) {
            std::cerr << "无法打开文件: " << filename << std::endl;
            return false;
        }
        
        ret = avformat_find_stream_info(fmt_ctx, nullptr);
        if (ret < 0) {
            std::cerr << "无法获取流信息" << std::endl;
            return false;
        }
        
        video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
        if (video_stream_index < 0) {
            std::cerr << "未找到视频流" << std::endl;
            return false;
        }
        
        AVStream* video_stream = fmt_ctx->streams[video_stream_index];
        const AVCodec* codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
        if (!codec) {
            std::cerr << "未找到解码器" << std::endl;
            return false;
        }
        
        codec_ctx = avcodec_alloc_context3(codec);
        if (!codec_ctx) {
            std::cerr << "无法分配解码器上下文" << std::endl;
            return false;
        }
        
        ret = avcodec_parameters_to_context(codec_ctx, video_stream->codecpar);
        if (ret < 0) {
            std::cerr << "无法复制编解码器参数" << std::endl;
            return false;
        }
        
        ret = avcodec_open2(codec_ctx, codec, nullptr);
        if (ret < 0) {
            std::cerr << "无法打开解码器" << std::endl;
            return false;
        }
        
        // 初始化SDL
        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
            std::cerr << "无法初始化SDL: " << SDL_GetError() << std::endl;
            return false;
        }
        
        // 创建窗口
        window = SDL_CreateWindow("FFmpeg视频播放器", 
                                  SDL_WINDOWPOS_UNDEFINED, 
                                  SDL_WINDOWPOS_UNDEFINED,
                                  codec_ctx->width, 
                                  codec_ctx->height,
                                  SDL_WINDOW_RESIZABLE);
        if (!window) {
            std::cerr << "无法创建窗口: " << SDL_GetError() << std::endl;
            return false;
        }
        
        // 创建渲染器
        renderer = SDL_CreateRenderer(window, -1, 0);
        if (!renderer) {
            std::cerr << "无法创建渲染器: " << SDL_GetError() << std::endl;
            return false;
        }
        
        // 创建纹理
        texture = SDL_CreateTexture(renderer,
                                   SDL_PIXELFORMAT_YV12,
                                   SDL_TEXTUREACCESS_STREAMING,
                                   codec_ctx->width,
                                   codec_ctx->height);
        if (!texture) {
            std::cerr << "无法创建纹理: " << SDL_GetError() << std::endl;
            return false;
        }
        
        // 创建帧转换上下文
        sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
                                 codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P,
                                 SWS_BILINEAR, nullptr, nullptr, nullptr);
        if (!sws_ctx) {
            std::cerr << "无法创建转换上下文" << std::endl;
            return false;
        }
        
        // 分配帧
        frame = av_frame_alloc();
        yuv_frame = av_frame_alloc();
        
        int buffer_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, 
                                                    codec_ctx->width, 
                                                    codec_ctx->height, 1);
        buffer = (uint8_t*)av_malloc(buffer_size);
        
        av_image_fill_arrays(yuv_frame->data, yuv_frame->linesize, buffer,
                            AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height, 1);
        
        return true;
    }
    
    void play() {
        if (!fmt_ctx) {
            std::cerr << "请先打开文件" << std::endl;
            return;
        }
        
        is_playing = true;
        AVPacket* packet = av_packet_alloc();
        
        while (is_playing) {
            SDL_Event event;
            while (SDL_PollEvent(&event)) {
                handle_event(event);
            }
            
            if (av_read_frame(fmt_ctx, packet) >= 0) {
                if (packet->stream_index == video_stream_index) {
                    int ret = avcodec_send_packet(codec_ctx, packet);
                    if (ret >= 0) {
                        ret = avcodec_receive_frame(codec_ctx, frame);
                        if (ret == 0) {
                            display_frame();
                            
                            // 控制播放速度
                            double fps = av_q2d(av_guess_frame_rate(fmt_ctx, 
                                                                   fmt_ctx->streams[video_stream_index], 
                                                                   nullptr));
                            std::this_thread::sleep_for(
                                std::chrono::milliseconds(static_cast<int>(1000.0 / fps))
                            );
                        }
                    }
                }
                av_packet_unref(packet);
            } else {
                // 播放结束
                break;
            }
        }
        
        av_packet_free(&packet);
    }
    
    void stop() {
        is_playing = false;
    }
    
private:
    void display_frame() {
        sws_scale(sws_ctx, frame->data, frame->linesize,
                  0, codec_ctx->height, yuv_frame->data, yuv_frame->linesize);
        
        SDL_UpdateYUVTexture(texture, nullptr,
                           yuv_frame->data[0], yuv_frame->linesize[0],
                           yuv_frame->data[1], yuv_frame->linesize[1],
                           yuv_frame->data[2], yuv_frame->linesize[2]);
        
        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, texture, nullptr, nullptr);
        SDL_RenderPresent(renderer);
    }
    
    void handle_event(const SDL_Event& event) {
        switch (event.type) {
            case SDL_QUIT:
                stop();
                break;
            case SDL_KEYDOWN:
                switch (event.key.keysym.sym) {
                    case SDLK_SPACE:
                        is_playing = !is_playing;
                        break;
                    case SDLK_ESCAPE:
                        stop();
                        break;
                }
                break;
        }
    }
    
    void cleanup() {
        if (sws_ctx) {
            sws_freeContext(sws_ctx);
            sws_ctx = nullptr;
        }
        
        if (yuv_frame) {
            av_frame_free(&yuv_frame);
            yuv_frame = nullptr;
        }
        
        if (frame) {
            av_frame_free(&frame);
            frame = nullptr;
        }
        
        if (buffer) {
            av_free(buffer);
            buffer = nullptr;
        }
        
        if (texture) {
            SDL_DestroyTexture(texture);
            texture = nullptr;
        }
        
        if (renderer) {
            SDL_DestroyRenderer(renderer);
            renderer = nullptr;
        }
        
        if (window) {
            SDL_DestroyWindow(window);
            window = nullptr;
        }
        
        if (codec_ctx) {
            avcodec_free_context(&codec_ctx);
            codec_ctx = nullptr;
        }
        
        if (fmt_ctx) {
            avformat_close_input(&fmt_ctx);
            fmt_ctx = nullptr;
        }
        
        SDL_Quit();
    }
    
    AVFormatContext* fmt_ctx;
    AVCodecContext* codec_ctx;
    int video_stream_index;
    
    SDL_Window* window;
    SDL_Renderer* renderer;
    SDL_Texture* texture;
    
    SwsContext* sws_ctx;
    AVFrame* frame;
    AVFrame* yuv_frame;
    uint8_t* buffer;
    
    bool is_playing;
};

int main(int argc, char* argv[]) {
    if (argc < 2) {
        std::cerr << "使用方法: " << argv[0] << " <视频文件>" << std::endl;
        return 1;
    }
    
    init_ffmpeg();
    
    VideoPlayer player;
    if (!player.open(argv[1])) {
        return 1;
    }
    
    std::cout << "🎬 视频播放器已启动" << std::endl;
    std::cout << "控制说明：" << std::endl;
    std::cout << "  空格键: 播放/暂停" << std::endl;
    std::cout << "  ESC键: 退出" << std::endl;
    
    player.play();
    
    return 0;
}
